package com.lemzdo.community.service.impl;

import com.lemzdo.community.dto.CommentUserDTO;
import com.lemzdo.community.dto.PostDTO;
import com.lemzdo.community.enums.CommentTypeEnum;
import com.lemzdo.community.enums.NoticeStatusEnum;
import com.lemzdo.community.enums.NoticeTypeEnum;
import com.lemzdo.community.exception.CustomizeException;
import com.lemzdo.community.exception.ErrCodeEnum;
import com.lemzdo.community.mapper.CommentMapper;
import com.lemzdo.community.model.Comment;
import com.lemzdo.community.model.CommentExample;
import com.lemzdo.community.model.Post;
import com.lemzdo.community.model.User;
import com.lemzdo.community.service.CommentService;
import com.lemzdo.community.service.NoticeService;
import com.lemzdo.community.service.PostService;
import com.lemzdo.community.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {

    @Autowired//注入commentMapper持久层用于操作数据库
    private CommentMapper commentMapper;

    @Autowired//注入post的service层用于对post进行操作
    private PostService postService;

    @Autowired//注入user的service层用于对user进行操作
    private UserService userService;

    @Autowired//注入notice的service层用于对notice进行操作
    private NoticeService noticeService;

    /**
     *通过前端传回来的信息 封装成comment类对象
     * 根据postId（即对应的帖子/评论）判断所评论的帖子或者回复是否还存在
     * 根据type（即评论类型）判断评论的类型是一级或者二级评论（评论原贴/评论楼中楼）
     *
     * @param comment 评论model类对象 存放数据
     */
    @Override
    @Transactional
    public void insert(Comment comment) {

        //判断postId 空或者0表示前端返回的信息错误
        if (comment.getPostId() == null || comment.getPostId() == 0) {
            //若帖子被删除不存在了 返回相应的code和mssage
            throw new CustomizeException(ErrCodeEnum.COMMENT_ERR);
        }

        //判断评论的类型
        if (comment.getType() == null || !CommentTypeEnum.isExist(comment.getType())) {
            //若为空，或者不在枚举中 就返回相应的信息
            throw new CustomizeException(ErrCodeEnum.TYPE_PARAM_WRONG);
        }

        //根据类型作出不同的反应 需要分别根据postId（帖子id/评论id）操作
        if (comment.getType().equals(CommentTypeEnum.COMMENT_TYPE_1.getTypeCode())) {
            //评论类型是1级评论 即评论帖子的
            //点进帖子进行评论操作，帖子id数据库中肯定存在，需要判断帖子是否被删除
            PostDTO postDTO = postService.selectByPrimaryKey(comment.getPostId());
            if(postDTO==null){
                //评论的帖子已经删除
                throw new CustomizeException(ErrCodeEnum.POST_NOT_FOUND);
            }
            //插入数据到comment表
            commentMapper.insertSelective(comment);
            //需要对帖子的评论数+1 即Post的commentCount
            postService.increaseComment(postDTO.getId());

            //发起通知 对帖子进行了评论
            //发起通知人的id 接受通知人的id 帖子或者评论的id 通知的类型
            noticeService.createNotice(comment.getAuthorId(),postDTO.getAuthorId(),
                    postDTO.getId(), NoticeTypeEnum.REPLY_POST);


        } else {
            //评论类型是2级评论 即楼中楼 评论回复的
            //查询所评论的这个回复是否被删除
            //取出该评论的postId(所评论的帖子或者回复的id)对应的评论
            Comment dbComment = commentMapper.selectByPrimaryKey(comment.getPostId());
            //进行判断
            if(dbComment==null){
                //所回复的评论不存在了
                throw new CustomizeException(ErrCodeEnum.COMMENT_NOT_FOUND);
            }
            //评论存在的时候需要判断整个帖子是否还存在
            PostDTO postDTO = postService.selectByPrimaryKey(dbComment.getPostId());
            if(postDTO==null){
                //整个帖子都不存在了
                throw new CustomizeException(ErrCodeEnum.POST_NOT_FOUND);
            }
            //插入数据
            commentMapper.insertSelective(comment);
            //新增回复的评论数 即dbComment 的commentCount自增
            commentMapper.increaseCommentCountById(dbComment.getId());

            //发起通知 对评论进行了评论
            //发起通知人的id 接受通知人的id 帖子或者评论的id 通知的类型
            noticeService.createNotice(comment.getAuthorId(),dbComment.getAuthorId(),
                    dbComment.getId(), NoticeTypeEnum.REPLY_COMMENT);

        }

    }

    /**
     *  根据帖子的id查询出评论该帖子的所有1级评论,以及该评论对应的用户（需要头像和姓名）
     *  或者 根据评论的id查询出评论的二级评论，以及二级评论对应的用户
     * @param postId 帖子的id或者评论id
     * @return 所有评论即用户 自定义的dto
     */
    @Override
    public List<CommentUserDTO> selectAllByPostId(Integer postId,CommentTypeEnum typeEnum) {

        //查出帖子id或者评论id 对应的1/2级评论
        CommentExample example = new CommentExample();
        example.createCriteria().andPostIdEqualTo(postId).andTypeEqualTo(typeEnum.getTypeCode());
        List<Comment> comments = commentMapper.selectByExample(example);


        /**
         * 暴力方法 遍历所有comment然后依次查询数据，查询对应的user，存入dto中，再加入list中
         * 数据量大的时候一次select操作繁琐，服务器压力大
         */
      /*  //新建一个自定义的dtoList用于存放需要的数据
        List<CommentUserDTO> commentUserDTOS = new ArrayList<>();

        //遍历帖子的评论
        for (Comment comment : comments) {
            //新建一个自定义的dto 用于存放数据 再放入list中
            //不能定义在外面 不然每次存入list的都是同一个commentUserDTO，同一个地址
            //会将原来的数据覆盖 定义在里面 每次新建一个，地址不同，可以避免这个问题
            CommentUserDTO commentUserDTO = new CommentUserDTO();

            //将comment中数据放入commentUserDTO
            BeanUtils.copyProperties(comment,commentUserDTO);

            //将对应的user也放入commentUserDTO
            User user = userService.selectByPrimaryKey(comment.getAuthorId());
            commentUserDTO.setUser(user);

            //将commentUserDTO放入list中
            commentUserDTOS.add(commentUserDTO);
        }*/

        /**
         * java8新特性 使用lambada表达式直接获取需要的值，并放入list或者map中，便于存取，降低时间复杂度
         */

        if (comments.size() == 0) {
            return new ArrayList<>();
        }
        // 使用lambada表达式  获取去重的评论人的id
       // Set<Integer> commentators = comments.stream().map(comment -> comment.getAuthorId()).collect(Collectors.toSet());
        //上面->可以写成下面这种形式
        Set<Integer> commentators = comments.stream().map(Comment::getAuthorId).collect(Collectors.toSet());
        List<Integer> userIds = new ArrayList<>();
        userIds.addAll(commentators);
        //上面 三步可以合成下面一步
        //List<Integer> userIds = comments.stream().map(Comment::getAuthorId).distinct().collect(Collectors.toList());


        // 获取评论人并转换为 Map 后面一次获取到可以降低时间复杂度
        List<User> users = userService.selectUsersByUserIds(userIds);
        //Map<Integer, User> userMap = users.stream().collect(Collectors.toMap(user -> user.getId(), user -> user));
        Map<Integer, User> userMap = users.stream().collect(Collectors.toMap(User::getId, user -> user));


        // 转换 comment 为 commentDTO
        List<CommentUserDTO> commentUserDTOS = comments.stream().map(comment -> {
            CommentUserDTO commentUserDTO = new CommentUserDTO();
            BeanUtils.copyProperties(comment, commentUserDTO);
            commentUserDTO.setUser(userMap.get(comment.getAuthorId()));
            return commentUserDTO;
        }).collect(Collectors.toList());

        return commentUserDTOS;
    }

    /**
     * 根据1级评论的id 找到对应的帖子
     * @param commentId 1级评论的id(唯一)
     * @return 帖子信息
     */
    @Override
    public Post getPostByCommentId(Integer commentId) {

        //根据评论id 找到评论信息 里面有postId
        CommentExample example = new CommentExample();
        example.createCriteria().andIdEqualTo(commentId);
        Comment comment = commentMapper.selectByExample(example).get(0);

        //根据postId 查询post信息,并返回
        return postService.getPostById(comment.getPostId());
    }
}
